package com.second.app.superthread;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author GYZ
 * @Date 2023/12/29
 * <pre>
 *   Semaphore: 信号，信号系统 主要是限制线程的并发数量。如果不限制线程的并发数量，CPU的资源则很快就被耗尽
 *   每个线程的任务相当缓慢，因为cpu要把时间切片分配给不同的线程对象。而且上下文切换也比较耗时，最终造成系统运行效率
 *   大大降低，所以限制并发线程的数量还是非常有必要的。
 *
 *  案例2：
 *    Semaphore构造方法permits参数作用，permits设置=2，同一时间
 *    只有2个线程可以同时执行acquire和release。如果permits大于1，该类并不能保证线程安全性，因为
 *    还是有可能会出现多个线程共同访问实例变量，导致脏数据的情况。
 *  案例3：
 *    acquire(int permits)
 *    一共10个许可，每次执行acquire(2)代码时，耗费掉2个。所以10/2=5；
 *    说明同一时间只有5个线程允许执行acquire和release的代码
 *  案例4：
 *    acquireUninterruptibly():使等待进入acquire方法的线程，不允许被中断。
 *  案例5：
 *     公平与非公平信号量的测试 有些时候获取许可的顺序和线程启动的顺序有关，这时候 信号量就要
 *     分为公平和非公平的。所谓的公平信号量是指获得锁的顺序与线程启动的顺序有关，但不代表百分之一百获得信号量，仅仅是概率上得到保证
 *     而非公平信号量就是无关的了。
 *  案例6
 *    允许多个线程同时访问
 *  案例7
 *    多进路-多处理-多出路实验 运行的效果是多个线程同时进入
 *    多个线程又几乎同时执行完毕
 *  案例8
 *    停车场停车
 *    5辆车  但是只能同时有3辆车停进来 需要控制流量
 *    打印输出结果：
 *      Thread-0停车入位，耗时3秒
 *      Thread-1停车入位，耗时1秒
 *      Thread-2停车入位，耗时3秒
 *
 *      Thread-1车辆离场，耗时1秒
 *
 *      Thread-3停车入位，耗时2秒
 *
 *      Thread-2车辆离场，耗时2秒
 *      Thread-0车辆离场，耗时2秒
 *
 *      Thread-4停车入位，耗时1秒
 *      Thread-4车辆离场，耗时1秒
 *
 *      Thread-3车辆离场，耗时3秒
 *   案例9
 *      使用semaphore创建字符串池
 *         类semaphore可以有效的对并发执行任务的线程数量进行限制，这种功能可以应用在pool池技术中，
 *         可以设置同时访问pool池中数据的线程数量
 * </pre>
 */

//案例9
class ListPool {
    private static final int poolMaxSize = 3;
    private static final int semaphorePermits = 5;
    private static final List<String> list = new ArrayList<>();
    private static final Semaphore concurrentcySemaphore = new Semaphore(semaphorePermits);
    private static final ReentrantLock reentrantLock = new ReentrantLock();
    private static final Condition condition = reentrantLock.newCondition();

    public ListPool() {
        for (int i = 0; i < poolMaxSize; i++) {
            list.add("高洪岩" + (i + 1));
        }
    }

    public String get() {
        String getString = null;
        try {
            concurrentcySemaphore.acquire();
            reentrantLock.lock();
            while (list.size() == 0) {
                condition.await();
            }
            getString = list.remove(0);
            reentrantLock.unlock();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return getString;
    }

    public void put(String stringValue) {
        reentrantLock.lock();
        list.add(stringValue);
        condition.signalAll();
        reentrantLock.unlock();
        concurrentcySemaphore.release();
    }
}

class My001Thread extends Thread {

    private  final ListPool listPool;

    public My001Thread(ListPool listPool) {
        this.listPool = listPool;
    }

    @Override
    public void run() {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            String getString = listPool.get();
            System.out.println(Thread.currentThread().getName() + " 取得值" + getString);
            listPool.put(getString);

        }
    }
}

class Run9 {
    public static void main(String[] args) {
        ListPool listPool = new ListPool();
        My001Thread[] my001Threads = new My001Thread[12];
        for (int i = 0; i < my001Threads.length; i++) {
            my001Threads[i] = new My001Thread(listPool);
        }
        for (int i = 0; i < my001Threads.length; i++) {
            my001Threads[i].start();
        }
    }
}

//案例8
class ParkCarDemo {
    public static void main(String[] args) {

        Semaphore parkAdmin = new Semaphore(3);
        Runnable parkCarRunnable = () -> {
            try {
                parkAdmin.acquire();

                String name = Thread.currentThread().getName();

                Random random = new Random();

                int seconds = random.nextInt(3) + 1;

                System.out.println(name + "停车入位，耗时" + seconds + "秒");

                seconds = random.nextInt(3) + 1;

                Thread.sleep(seconds * 1000);

                parkAdmin.release();

                System.out.println(name + "车辆离场，耗时" + seconds + "秒");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        for (int i = 0; i < 5; i++) {
            new Thread(parkCarRunnable).start();
        }
    }
}

//案例7
class ManyService {
    private Semaphore semaphore = new Semaphore(3);

    public void sayHello() {
        try {
            semaphore.acquire();
            System.out.println("ThreadName=" + Thread.currentThread().getName() + "准备");
            System.out.println("begin hello " + System.currentTimeMillis());
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "打印" + (i + 1));
            }
            System.out.println(" end hello " + System.currentTimeMillis());
            semaphore.release();
            System.out.println("ThreadName=" + Thread.currentThread().getName() + "结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Thread001 extends Thread {

    private final ManyService manyService;

    public Thread001(ManyService manyService) {
        this.manyService = manyService;
    }

    @Override
    public void run() {
        manyService.sayHello();
    }
}

class MainTest {
    public static void main(String[] args) {
        ManyService manyService = new ManyService();

        Thread001[] tread001Arr = new Thread001[12];

        for (int i = 0; i < tread001Arr.length; i++) {
            tread001Arr[i] = new Thread001(manyService);
            tread001Arr[i].start();
        }
    }
}

class SemaphoreExample {
    private static final int loopIndex = 200;

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(50);

        Semaphore semaphore = new Semaphore(20);

        for (int i = 0; i < loopIndex; i++) {
            final int threadNum = i;
            executorService.execute(() -> {
                try {
                    semaphore.acquire();//获取一个许可，所以可运行线程数量为20/1=20
                    test(threadNum);
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        executorService.shutdown();
        System.out.println("finish");
    }

    static void test(int threadNum) throws InterruptedException {
        Thread.sleep(1000);
        System.out.println("threadNum:" + threadNum);
        Thread.sleep(1000);
    }
}


class MyService {

    private boolean isFair = true;

    private final Semaphore semaphore = new Semaphore(1, isFair);

    public void testMethod() {
        try {
            semaphore.acquire();
            System.out.println("ThreadName=" + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();
        }
    }
}

class MyThread extends Thread {
    private MyService myService;

    public MyThread(MyService myService) {
        this.myService = myService;
    }

    @Override
    public void run() {
        System.out.println("ThreadName=" + this.getName() + "启动了！");
        myService.testMethod();
    }
}

class Run {
    public static void main(String[] args) {
        MyService myService = new MyService();

        MyThread firstThread = new MyThread(myService);

        firstThread.start();

        MyThread[] myThreads = new MyThread[4];

        for (int i = 0; i < 4; i++) {
            myThreads[i] = new MyThread(myService);
            myThreads[i].start();
        }
    }
}


//案例4
class Service4 {
    private Semaphore semaphore = new Semaphore(1);

    //    public void testMethod() {
//        try {
//            semaphore.acquire();
//            System.out.println(Thread.currentThread().getName() + " begin timer=" + System.currentTimeMillis());
//            for (int i = 0; i < Integer.MAX_VALUE; i++) {
//                String newString = new String();
//                Math.random();
//            }
//            System.out.println(Thread.currentThread().getName() + " end timer=" + System.currentTimeMillis());
//            semaphore.release();
//        } catch (InterruptedException e) {
//            System.out.println("线程：" + Thread.currentThread().getName() + "进入了catch");
//            e.printStackTrace();
//        }
//    }
    public void testMethod() {

        semaphore.acquireUninterruptibly();
        System.out.println(Thread.currentThread().getName() + " begin timer=" + System.currentTimeMillis());
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            String newString = new String();
            Math.random();
        }
        System.out.println(Thread.currentThread().getName() + " end timer=" + System.currentTimeMillis());
        semaphore.release();

    }
}

class ThreadAAA extends Thread {

    private Service4 service4;

    public ThreadAAA(Service4 service4) {
        this.service4 = service4;
    }

    @Override
    public void run() {
        service4.testMethod();
    }
}

class ThreadBBB extends Thread {

    private Service4 service4;

    public ThreadBBB(Service4 service4) {
        this.service4 = service4;
    }

    @Override
    public void run() {
        service4.testMethod();
    }
}

class Demo4 {
    public static void main(String[] args) throws InterruptedException {
        Service4 service4 = new Service4();
        ThreadAAA threadAAA = new ThreadAAA(service4);
        threadAAA.setName("A");
        threadAAA.start();
        ThreadBBB threadBBB = new ThreadBBB(service4);
        threadBBB.setName("B");
        threadBBB.start();

        Thread.sleep(1000);

        threadBBB.interrupt();

        System.out.println("main 中断了a");

    }
}

//案例3
class Service3 {
    private Semaphore semaphore = new Semaphore(10);

    public void testMethod() {
        try {
            semaphore.acquire(2);
            System.out.println(Thread.currentThread().getName() + " begin timer=" + System.currentTimeMillis());
            int sleepValue = (int) (Math.random() * 10000);
            System.out.println(Thread.currentThread().getName() + " 停止了" + (sleepValue / 1000) + "秒");
            Thread.sleep(sleepValue);
            System.out.println(Thread.currentThread().getName() + " end timer=" + System.currentTimeMillis());
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class ThreadWx extends Thread {

    private Service3 service3;

    public ThreadWx(Service3 service3) {
        this.service3 = service3;
    }

    @Override
    public void run() {
        service3.testMethod();
    }
}

class Demo3 {
    public static void main(String[] args) {
        Service3 service3 = new Service3();

        ThreadWx[] threadWxes = new ThreadWx[10];

        for (int i = 0; i < 10; i++) {
            threadWxes[i] = new ThreadWx(service3);

            threadWxes[i].start();
        }
    }
}
//////////////////////////////////////////////////////////////////


//案例2
class Service2 {
    //同一时间最多允许2个线程执行acquire和release
    private Semaphore semaphore = new Semaphore(2);

    public void testMethod() {
        try {
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName() + " begin timer=" + System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println(Thread.currentThread().getName() + " end timer=" + System.currentTimeMillis());
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class ThreadAA extends Thread {
    private Service2 service2;

    public ThreadAA(Service2 service2) {
        this.service2 = service2;
    }

    @Override
    public void run() {
        service2.testMethod();
    }
}

class ThreadBB extends Thread {
    private Service2 service2;

    public ThreadBB(Service2 service2) {
        this.service2 = service2;
    }

    @Override
    public void run() {
        service2.testMethod();
    }
}

class ThreadCC extends Thread {
    private Service2 service2;

    public ThreadCC(Service2 service2) {
        this.service2 = service2;
    }

    @Override
    public void run() {
        service2.testMethod();
    }
}

class MainD {
    public static void main(String[] args) {
        Service2 service = new Service2();
        ThreadAA threadA = new ThreadAA(service);
        threadA.setName("a");
        ThreadBB threadB = new ThreadBB(service);
        threadB.setName("b");
        ThreadCC threadC = new ThreadCC(service);
        threadC.setName("c");
        threadA.start();
        threadB.start();
        threadC.start();
    }
}


///////////////////////////////////////////////////////////////////
public class SemaphoreDemo {
}

class Service {
    private Semaphore semaphore = new Semaphore(1);

    public void testMethod() {
        try {
            semaphore.tryAcquire();
            ;
            System.out.println(Thread.currentThread().getName() + "begin timer=" + System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println(Thread.currentThread().getName() + "end timer=" + System.currentTimeMillis());
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class ThreadA extends Thread {
    private Service service;

    public ThreadA(Service service) {
        this.service = service;
    }

    @Override
    public void run() {
        service.testMethod();
    }
}

class ThreadB extends Thread {
    private Service service;

    public ThreadB(Service service) {
        this.service = service;
    }

    @Override
    public void run() {
        service.testMethod();
    }
}

class ThreadC extends Thread {
    private Service service;

    public ThreadC(Service service) {
        this.service = service;
    }

    @Override
    public void run() {
        service.testMethod();
    }
}

class Main {
    public static void main(String[] args) {
        Service service = new Service();
        ThreadA threadA = new ThreadA(service);
        threadA.setName("a");
        ThreadB threadB = new ThreadB(service);
        threadB.setName("b");
        ThreadC threadC = new ThreadC(service);
        threadC.setName("c");
        threadA.start();
        threadB.start();
        threadC.start();
    }
}